package com.dave.gd.core.base.entity.impl;

import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import com.dave.gd.common.util.ClassInfoUtils;
import com.dave.gd.common.util.StringUtils;
import com.dave.gd.core.base.entity.IAttrSpec;
import com.dave.gd.core.base.entity.OpType;
import com.dave.gd.core.contants.BaseUnitConstants;
import com.dave.gd.core.util.RetInfo;
import com.dave.gd.core.util.SqlDealUtil;

/**
 * Created by linzq on 2014/11/23.
 */
@SuppressWarnings("serial")
public abstract class AbstractDynamicBaseEntity<ID extends Serializable>
    extends AbstractBaseEntity<ID> {
    
    public AbstractDynamicBaseEntity() {
        super();
    }
    
    public AbstractDynamicBaseEntity(Boolean genId) {
        super(genId);
    }
    
    private List<EntityInstAttr> entityInstAttrs = new ArrayList<EntityInstAttr>();
    
    public abstract Class<? extends EntityInstAttr> getAttrEntity();
    
    public List<EntityInstAttr> getEntityAttrs() {
        if (this.entityInstAttrs != null && this.entityInstAttrs.size() > 0) {
            return this.entityInstAttrs;
        }
        StringBuffer sql = new StringBuffer();
        //        EntityInstAttr attr = (EntityInstAttr) EntityInsFactory.getInstance(this.getAttrEntity());
        //        sql.append("SELECT " + SqlDealUtil.createColumn(attr.tablename(), "") + " FROM "
        //            + attr.tablename() + " WHERE " + this.id() + " = ?");
        sql.append("SELECT "
            + SqlDealUtil.createColumn(ClassInfoUtils.getTableName(this.getAttrEntity()), "")
            + " FROM " + ClassInfoUtils.getTableName(this.getAttrEntity()) + " WHERE "
            + ClassInfoUtils.getIdField(this.getAttrEntity()) + " = ?");
        List<Object> params = new ArrayList<Object>();
        params.add(this.getId());
        List<EntityInstAttr> list = (List<EntityInstAttr>) defaultRepository().jdbcFindList(
            sql.toString(), this.getAttrEntity(), params);
        
        if (this.entityInstAttrs == null) {
            this.entityInstAttrs = new ArrayList<EntityInstAttr>();
        }
        this.entityInstAttrs.clear();
        this.entityInstAttrs.addAll(list);
        
        // 初始化owner
        for (EntityInstAttr instAttr : this.entityInstAttrs) {
            instAttr.setOwnerEntity(this);
        }
        
        return this.entityInstAttrs;
    }
    
    @Override
    public int remove() {
        for (EntityInstAttr attr : this.getEntityAttrs()) {
            attr.remove();
        }
        return super.remove();
    }
    
    @Override
    public int save() {
        for (EntityInstAttr attr : this.getEntityAttrs()) {
            attr.save();
        }
        return super.save();
    }
    
    @Override
    public int update() {
        for (EntityInstAttr attr : this.getEntityAttrs()) {
            if (attr.getEnttOpType() != null) {
                if (attr.getEnttOpType().equals(OpType.ADD)) {
                    attr.save();
                } else if (attr.getEnttOpType().equals(OpType.MOD)) {
                    attr.update();
                } else if (attr.getEnttOpType().equals(OpType.DEL)) {
                    attr.remove();
                }
            }
        }
        return super.update();
    }
    
    @Override
    public RetInfo set(IAttrSpec attrSpec, Object value, boolean check) {
        RetInfo retInfo = RetInfo.newInstance();
        retInfo.setResult(BaseUnitConstants.RET_TRUE);
        
        StringBuffer setMsg = new StringBuffer();
        Object oldValue = "";
        boolean bSetted = false;
        if (attrSpec == null) {
            throw new RuntimeException("传入的属性ID或规格 ，无对应的元数据配置");
        }
        // 静态属性
        if (!attrSpec.getIsDany()) {
            retInfo = super.set(attrSpec, value, check);
            bSetted = true;
        } else {
            // 设置时， 属性取值规则约束判断
            //set 前置规则校验， 如果不成立不再执行
            if (check == true && !this.beforeSet(attrSpec, value, setMsg)) {
                retInfo.setRetCodeMsg(BaseUnitConstants.RET_FALSE, setMsg.toString());
                return retInfo;
            }
            // 使用this.getRemainAttrs()获取除删除外的所有属性
            EntityInstAttr<?> attr = getAttrBySpec(this.getRemainAttrs(), attrSpec);
            
            Object valueToUi = value;
            if (!StringUtils.isNullOrEmpty(value) && value instanceof String) {
                valueToUi = attrSpec.convertToUI((String) value, this);
                //当转换后为空，则无需转换，避免关联型属性被转换为空
                if (StringUtils.isNullOrEmpty(valueToUi)) {
                    valueToUi = value;
                }
            }
            
            if (attr != null) {
                oldValue = attr.getValue();
                //添加convertToBean为空的判断，避免属性实例中attrValue为空的数据存在
                if (StringUtils.isNullOrEmpty(value)
                    || StringUtils.isNullOrEmpty(attrSpec.convertToBean(valueToUi))) {
                    this.removeAttr(attr);
                } else if ((oldValue != null && !oldValue.equals(valueToUi))
                    || (valueToUi != null && !valueToUi.equals(oldValue))) {
                    // TODO 这是要实时保存？
                    this.modAttr(attr, valueToUi);
                    bSetted = true;
                }
                // TODO 多次修改和初始值相同？
            } else if (attr == null && !StringUtils.isNullOrEmpty(value)
                && !StringUtils.isNullOrEmpty(attrSpec.convertToBean(valueToUi))) { //添加convertToBean为空的判断，避免属性实例中attrValue为空的数据存在
                //从删除列表中获取，如果有，则重新添加到列表中
                attr = getAttrBySpec(this.getRemoveAttrs(), attrSpec);
                if (attr != null) {
                    // 先删除，重新设值，如果值相同，则还原属性；如果不同则设置为属性修改
                    if (valueToUi.equals(attr.getValue())) {
                        this.recoverAttr(attr);
                    } else {
                        this.modAttr(attr, valueToUi);
                    }
                } else {
                    this.addAttr(attrSpec, valueToUi);
                }
                bSetted = true;
            }
            
            if (check == true && bSetted) {
                //后置set 规则， 触发关联变更
                boolean result = afterSet(attrSpec, value, setMsg);
                if (!result) {
                    retInfo.setRetCodeMsg(BaseUnitConstants.RET_FALSE, setMsg.toString());
                    return retInfo;
                }
            }
            
        }
        
        return retInfo;
    }
    
    @Override
    public Object get(IAttrSpec attrSpec) {
        Object value = null;
        if (attrSpec == null) {
            throw new RuntimeException("传入的属性ID或规格 ，无对应的元数据配置");
        }
        
        if (!attrSpec.getIsDany()) {
            return super.get(attrSpec);
        } else {
            EntityInstAttr attr = getAttrBySpec(this.getEntityAttrs(), attrSpec);
            
            if (attr != null) {
                return attr.getValue();
            }
        }
        
        return value;
    }
    
    /**
     * 属性和属性规格
     * .
     * getAttrBySpec
     * .	
     * @param instAttrs
     * @param attrs
     * @return
     * @date 2014年11月29日
     *
     */
    protected EntityInstAttr getAttrBySpec(List<EntityInstAttr> instAttrs, IAttrSpec attrs) {
        
        for (Iterator<EntityInstAttr> itAttr = instAttrs.iterator(); itAttr.hasNext();) {
            
            EntityInstAttr attr = itAttr.next();
            if (attr == null || attr.getAttrSpec() == null) {
                continue;
            }
            if (attr.getAttrSpec().getId().equals(attrs.getId())) {
                return attr;
            }
        }
        return null;
    }
    
    protected void removeAttr(EntityInstAttr<?> attrInst) {
        // 非新增属性
        if (!attrInst.getIsNewEnitity()) {
            attrInst.setEnttOpType(OpType.DEL);
        } else {
            // 新增属性，直接删除
            removeAttrDirectly(attrInst);
        }
        
    }
    
    protected void removeAttrDirectly(EntityInstAttr<?> attrInst) {
        this.getEntityAttrs().remove(attrInst);
    }
    
    // 之后转移到util中...
    protected void addAttr(IAttrSpec attrSpec, Object value) {
        try {
            EntityInstAttr attrInst = createAttr(attrSpec);
            // 设置属性规格、属性是否为新建、动作、归属实体
            attrInst.setAttrSpec(attrSpec);
            attrInst.setIsNewEntity(true);
            attrInst.setEnttOpType(OpType.ADD);
            attrInst.setOwnerEntity(this);
            attrInst.setValue(value);
            
            this.getEntityAttrs().add(attrInst);
        } catch (Exception e) {
            throw new RuntimeException(this.getAttrEntity().getName() + "创建失败");
        }
        
    }
    
    protected EntityInstAttr createAttr(IAttrSpec attrSpec)
        throws NoSuchMethodException, SecurityException, InstantiationException,
        IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        Class<? extends EntityInstAttr> attrEntity = this.getAttrEntity();
        attrEntity.getConstructors();
        Constructor<? extends EntityInstAttr> c = attrEntity.getConstructor(Boolean.class);
        return c.newInstance(true);
    }
    
    protected void modAttr(EntityInstAttr<?> attrInst, Object newValue) {
        // 如果是新增属性，修改属性值，属性的动作仍为新增
        if (attrInst.getIsNewEnitity()) {
            attrInst.setValue(newValue);
        } else {
            attrInst.setEnttOpType(OpType.MOD);
            attrInst.setValue(newValue);
        }
    }
    
    protected void recoverAttr(EntityInstAttr<?> attrInst) {
        attrInst.setEnttOpType(null);
    }
    
    public List<EntityInstAttr> getRemoveAttrs() {
        return getAttrsByOpType(OpType.DEL);
    }
    
    public List<EntityInstAttr> getModAttrs() {
        return getAttrsByOpType(OpType.MOD);
    }
    
    public List<EntityInstAttr> getAddAttrs() {
        return getAttrsByOpType(OpType.ADD);
    }
    
    public List<EntityInstAttr> getRemainAttrs() {
        return getAttrsByExpOpType(OpType.DEL);
    }
    
    public List<EntityInstAttr> getAttrsByOpType(OpType type) {
        
        List<EntityInstAttr> allAttrInst = this.getEntityAttrs();
        List<EntityInstAttr> attrs = new ArrayList<EntityInstAttr>();
        if (allAttrInst != null && allAttrInst.size() > 0) {
            for (EntityInstAttr attrInst : allAttrInst) {
                if (attrInst != null && type != null && type.equals(attrInst.getEnttOpType())) {
                    attrs.add(attrInst);
                }
            }
        }
        return attrs;
    }
    
    public List<EntityInstAttr> getAttrsByExpOpType(OpType type) {
        
        List<EntityInstAttr> allAttrInst = this.getEntityAttrs();
        List<EntityInstAttr> attrs = new ArrayList<EntityInstAttr>();
        if (allAttrInst != null && allAttrInst.size() > 0) {
            for (EntityInstAttr attrInst : allAttrInst) {
                if (attrInst != null && type != null && !type.equals(attrInst.getEnttOpType())) {
                    attrs.add(attrInst);
                }
            }
        }
        return attrs;
    }
    
}
